package kMeans.core;

import gui.GUI;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;

public class KMeans {
	public KMeans() {
	}

	public void train(PadraoTreinamento[] aTreinamento, Cluster[] clustersK) {
	
		for (int i = 0; i < clustersK.length; i++) {
			//Zera os padroes associados ao cluster.
			clustersK[i].setPadroesAssociados(new ArrayList<PadraoTreinamento>());
		}
		
		for (int i = 0; i < aTreinamento.length; i++) {
			double euclideanDistance = 0.0;
			double distMin = 100000;
			int clusterMinId = 0;

			for (int j = 0; j < clustersK.length; j++) {
				ArrayList valoresPadrao = aTreinamento[i].getValoresPadrao();
				Iterator iteratorValoresPadrao = valoresPadrao.iterator();

				ArrayList posicaoCluster = clustersK[j].getClusterCenter();
				Iterator iteratorCentroCluster = posicaoCluster.iterator();

				// Calcula distancia Euclidiana entre o padrao e o centro dos
				// clusters, para definir o mais proximo.
				while (iteratorValoresPadrao.hasNext()) {
					Double valorDimensaoPadrao = (Double) iteratorValoresPadrao
							.next();
					Double valorCentroCluster = (Double) iteratorCentroCluster
							.next();

					euclideanDistance += Math.pow((valorDimensaoPadrao
							.doubleValue() - valorCentroCluster.doubleValue()),
							2);
				}

				euclideanDistance = Math.sqrt(euclideanDistance);

				// Guarda o ID do cluster mais proximo para que o padrao seja
				// atribuido com pertencendo a ele.
				if (euclideanDistance < distMin) {
					distMin = euclideanDistance;
					clusterMinId = j;
				}
			}

			clustersK[clusterMinId].incluirPadrao(aTreinamento[i]);
		}
	}

	public ArrayList test(PadraoTreinamento[] aTest, Cluster[] clustersK) {

		for (int i = 0; i < clustersK.length; i++) {
			//Zera os padroes associados ao cluster.
			clustersK[i].setPadroesAssociados(new ArrayList<PadraoTreinamento>());
		}
		
		int falsosPositivos = 0;
		int falsosNegativos = 0;

		ArrayList<Integer> novelty = new ArrayList<Integer>();
		
		for (int i = 0; i < aTest.length; i++) {
			double distMin = 100000;
			int clusterMinId = 0;

			for (int j = 0; j < clustersK.length; j++) {
				double euclideanDistance = 0.0;

				ArrayList valoresPadrao = aTest[i].getValoresPadrao();
				Iterator iteratorValoresPadrao = valoresPadrao.iterator();

				ArrayList posicaoCluster = clustersK[j].getClusterCenter();
				Iterator iteratorCentroCluster = posicaoCluster.iterator();

				// Calcula distancia Euclidiana entre o padrao e o centro dos
				// clusters, para definir o mais proximo.
				while (iteratorValoresPadrao.hasNext()) {
					Double valorDimensaoPadrao = (Double) iteratorValoresPadrao
							.next();
					Double valorCentroCluster = (Double) iteratorCentroCluster
							.next();

					euclideanDistance += Math.pow((valorDimensaoPadrao
							.doubleValue() - valorCentroCluster.doubleValue()),
							2);
				}

				euclideanDistance = Math.sqrt(euclideanDistance);

				// Guarda o ID do cluster mais proximo para que o padrao seja
				// atribuido com pertencendo a ele.
				if (euclideanDistance < distMin) {
					distMin = euclideanDistance;
					clusterMinId = j;
				}
			}

			if (distMin > clustersK[clusterMinId].getNoveltyDistance()) {
				//Se achou uma novidade, verifica a classe. Se for 1, e um falso positivo.
				if (aTest[i].getClasse() == 1) {
					falsosPositivos++;
				} 				
			} else {
				//Se nao achou uma novidade, verifica a classe. Se for 2, e um falso negativo.
				if (aTest[i].getClasse() == 2) {
					falsosNegativos++;					
				}
			}
			
			clustersK[clusterMinId].incluirPadrao(aTest[i]);
		}
	
		novelty.add(falsosPositivos);
		novelty.add(falsosNegativos);
		return novelty;
	}

	
	public boolean adjustCenter(Cluster[] clustersK, GUI pGUI) {
		String decimal = "0.0000";
		DecimalFormat df = new DecimalFormat(decimal);
		
		boolean [] isMoving = new boolean [clustersK.length];
		
		for (int i = 0; i < clustersK.length; i++) {
			isMoving[i] = clustersK[i].adjustCenter();
			if(pGUI != null) {
				pGUI.log("Cluster["+i+"] "+ df.format(clustersK[i].getClusterCenter().get(0)) + " "+ df.format(clustersK[i].getClusterCenter().get(1))+"  ");
			} else {
				System.out.print("Cluster["+i+"] "+ df.format(clustersK[i].getClusterCenter().get(0)) + " "+ df.format(clustersK[i].getClusterCenter().get(1))+"  ");
			}
		}
		
		if(pGUI != null) {
			pGUI.log("\n");
		} else {
			System.out.println();
		}
		
		for (int i = 0; i < isMoving.length; i++) {
			if (isMoving[i] ==  Boolean.TRUE) {
				return true;
			}
		}
		return false;
	}

}
